#package包
#即该版本的python软件包，会自动创建一个名为__init__.py的一个文件
"""
from test import testpackage1
'''
输出结果：
This is a package
this is package1
'''
"""
#与普通文件夹的区别就是会初始化生成一个文件
#在任何导入包内模块的操作时，都会执行__init__.py中的代码，
#作用：在test中需要共同执行的代码放在该文件中
#同时导入多个模块时，遵循先导入先执行的原则

from test import *
'''
输出结果：
This is a package
this is package1
（由于在__init__.py中定义了__all__=['testpackage1'],故使用*导入test中所有模块时没有导入testpackage2）
'''
#递归：此事在几天前的文件亦有记载
'''
对象引用和函数引用：
不可变对象：相同的值用同一个地址储存
同理：如果引用函数时函数收到的是可变对象，就能够直接对该变量修改值
如果是不可变对象，就不能够修改原始值
（类似于C中传值函数
c中的经典错误：
void exchange(int x,int y){
    int temp=x;
    x=y;
    y=temp;
}
实际上定义a=3,b=4,exchange(a,b)之后a,b的值没有变化，这就是因为这种函数调用只传递了a,b的值
想要实现传址，需要使用取地址符号&,写成exchange(int &x,int &y)）或exchange(int*p,int*q)
'''
#函数的引用：等号起别名
def test111():
    print('This is test111')
test111()
res=test111#This is test111
res()#This is test111
#闭包：典型结构如下：
def out(sum1):
    def inf():
        nonlocal sum1
        print(f'inf:{sum1+1}')
    return inf()
#1)函数的嵌套定义
#2）内层函数引用外层函数的非全局变量
#3）外层函数返回内层函数的函数名
'''
作用：1)保存一些不易改变或销毁的非全局变量
2）装饰器
3）实现数据锁定
'''
output=out
output(1)#输出inf:2
#装饰器：本质上是闭包函数，作用是在不改变原函数的代码的基础上添加新功能

def wrapper(function):
    def inner(*arg):
        print('开始计算：')
        function(*arg)
        print('计算结束')
    return inner
def add(x,y):
    print('{}+{}={}'.format(x,y,x+y))
re=wrapper(add)
re(1,2)
'''
开始计算：
1+2=3
计算结束
'''
#观察到，装饰器的作用是采用闭包的方式在内层函数中加入被装饰函数的其它功能
'''
上面的装饰器也可以写成：
@wrapper:
def add(x,y):
    print('{}+{}={}'.format(x,y,x+y))
add(1,2)
功能是一样的，即@外层函数起到了和引用外层函数相同的结果
'''
#优势：一个装饰器可以关联多个函数